<?php
/**
 * @package Curly
 * @version 0.9
 * @link http://curly.codeplex.com/
 * @license http://curly.codeplex.com/license The MIT License
 * @author Dawid Zawada
 */

namespace Curly
{
	use Curly\Collections\Collection;
	use Curly\Collections\StringIndexedCollection;
	use Curly\Cookies\CookieContainer;

    /**
     * Class representing a HTTP request
     * 
     * @package Curly
     * @license http://curly.codeplex.com/license The MIT License
     */
	class Request
    {
        /**
         * Request URI
         * 
         * @var string
         */
        protected $uri;
        
        /**
         * Request method
         * 
         * @var Curly\Method
         */
        protected $method;
        
        /**
         * HTTP protocol version
         * 
         * @var Curly\HttpVersion
         */
        protected $httpVersion;
        
        /**
         * Indication of whether redirections should be performed automatically 
         * 
         * @var bool
         */
        protected $allowAutoRedirect;
        
        /**
         * Maximum number of automatic redirections
         * 
         * @var int
         */
        protected $maxRedirections;
        
        /**
         * Path of the output file
         * 
         * @var string
         */
        protected $outputFilePath;
        
        /**
         * Referer header
         * 
         * @var string
         */
        protected $referer;
        
        /**
         * User agent header
         * 
         * @var string
         */
        protected $userAgent;
        
        /**
         * Maximum amount of time to wait while trying to connect (in seconds)
         * 
         * @var double
         */
        protected $connectionTimeout;
        
        /**
         * Maximum amount of time to wait while executing (in seconds)
         * 
         * @var double
         */
        protected $timeout;
        
        /**
         * HTTP authentication options
         * 
         * @var Curly\Authentication
         */
        protected $authentication;
        
        /**
         * Collection of cookies to send
         * 
         * @var Curly\Cookies\CookieContainer
         */
        protected $cookies;
        
        /**
         * Collection of files to upload
         * 
         * @var Curly\Collections\StringIndexedCollection
         */
        protected $files;
        
        /**
         * Collection of headers to add to the request
         * 
         * @var Curly\Collections\StringIndexedCollection
         */
        protected $headers;
        
        /**
         * Collection of additional options (used by client adapters)
         * 
         * @var Curly\Collections\Collection
         */
        protected $options;
        
        /**
         * Collection of POST vars
         * 
         * @var Curly\Collections\StringIndexedCollection
         */
        protected $postVars;
        
        /**
         * Proxy server options
         * 
         * @var Curly\Proxy
         */
        protected $proxy;
        
        /**
         * Indication of whether executing of the request is finished
         * 
         * @var bool
         */
        protected $isFinished;
        
        /**
         * Last occured error
         * 
         * @var Curly\Error
         */
        protected $error;
        
        /**
         * This request response
         * 
         * @var Curly\Response
         */
        protected $response;
        
        /**
         * Event fired when executing of this request finishes
         * 
         * @var Curly\RequestCompletedEvent
         */
        protected $requestCompletedEvent;
        
        /**
         * Creates a new Request with the given URI
         * 
         * @param string $uri
         * @param Curly\Method $method [optional]
         */
        public function __construct( $uri, Method $method = null )
        {
            $this->setUri( $uri );
            $this->setMethod( $method != null ? $method : Method::GET() );
            $this->setHttpVersion( HttpVersion::HTTP_1_1() );
            
            $this->setAutoRedirect( true );
            $this->setMaxRedirections( 20 );
            $this->setUserAgent( "Curly " . HttpClient::getVersion() );
            
            $this->authentication = new Authentication();
            $this->cookies = new CookieContainer();
            $this->files = new StringIndexedCollection();
            $this->headers = new StringIndexedCollection();
            $this->options = new Collection();
            $this->postVars = new StringIndexedCollection();
            $this->proxy = new Proxy();
            
            $this->requestCompletedEvent = new RequestCompletedEvent();
        }
        
        /**
         * Returns the request URI
         *
         * @return string
         */
        public function getUri()
        {
            return $this->uri;
        }
        
        /**
         * Sets the request URI
         * 
         * @param string $uri
         */
        protected function setUri( $uri )
        {
            $this->uri = (string)$uri;
        }
        
        /**
         * Returns the request method
         *
         * @return Curly\Method
         */
        public function getMethod()
        {
            return $this->method;
        }
        
        /**
         * Sets the request method
         * 
         * @param Curly\Method $method
         */
        public function setMethod( Method $method )
        {
            $this->method = $method;
        }
        
        /**
         * Returns the HTTP protocol version
         *
         * @return Curly\HttpVersion
         */
        public function getHttpVersion()
        {
            return $this->httpVersion;
        }
        
        /**
         * Sets the HTTP protocol version
         * 
         * @param Curly\HttpVersion $httpVersion
         */
        public function setHttpVersion( HttpVersion $httpVersion )
        {
            $this->httpVersion = $httpVersion;
        }
        
        /**
         * Indicates whether redirections should be performed automatically 
         *
         * @return bool
         */
        public function isAutoRedirect()
        {
            return $this->allowAutoRedirect;
        }
        
        /**
         * Sets the indication of whether redirections should be performed automatically
         * 
         * @param bool $allowAutoRedirect
         */
        public function setAutoRedirect( $allowAutoRedirect )
        {
            $this->allowAutoRedirect = (bool)$allowAutoRedirect;
        }
        
        /**
         * Returns the maximum number of automatic redirections
         *
         * @return int
         */
        public function getMaxRedirections()
        {
            return $this->maxRedirections;
        }
        
        /**
         * Sets the maximum number of automatic redirections
         * 
         * @param int $maxRedirections
         */
        public function setMaxRedirections( $maxRedirections )
        {
            $this->maxRedirections = (int)$maxRedirections;
        }
        
        /**
         * Returns the path of the output file
         * 
         * The output file is a file to which the response content
         * will be written
         *
         * @return string
         */
        public function getOutputFilePath()
        {
            return $this->outputFilePath;
        }
        
        /**
         * Sets the path of the output file
         * 
         * The output file is a file to which the response content
         * will be written
         * 
         * @param string $outputFilePath
         */
        public function setOutputFilePath( $outputFilePath )
        {
            $this->outputFilePath = (string)$outputFilePath;
        }
        
        /**
         * Indicates whether the output file has been specified
         *
         * @return bool
         */
        public function hasOutputFilePath()
        {
            return $this->getOutputFilePath() != "";
        }
        
        /**
         * Returns the refere
         *
         * @return string
         */
        public function getReferer()
        {
            return $this->referer;
        }
        
        /**
         * Sets the referer
         * 
         * @param string $referer
         */
        public function setReferer( $referer )
        {
            $this->referer = (string)$referer;
        }
        
        /**
         * Returns the user agent
         *
         * @return string
         */
        public function getUserAgent()
        {
            return $this->userAgent;
        }
        
        /**
         * Sets the user agent
         * 
         * @param string $userAgent
         */
        public function setUserAgent( $userAgent )
        {
            $this->userAgent = (string)$userAgent;
        }
        
        /**
         * Returns the connection timeout
         * 
         * Connection timeout is a maximum amount of time to wait 
         * while trying to connect (in seconds)
         *
         * @return double
         */
        public function getConnectionTimeout()
        {
            return $this->connectionTimeout;
        }
        
        /**
         * Sets the connection timeout
         * 
         * Connection timeout is a maximum amount of time to wait 
         * while trying to connect (in seconds)
         * 
         * The given connection timeout should be of type double or int
         * 
         * @param mixed $connectionTimeout
         */
        public function setConnectionTimeout( $connectionTimeout )
        {
            if( !is_double( $connectionTimeout ) && !is_int( $connectionTimeout ) )
            {
                $connectionTimeout = (int)$connectionTimeout;
            }
            
            $this->connectionTimeout = round( $connectionTimeout, 3 );
        }
        
        /**
         * Returns the timeout
         * 
         * Timeout is a maximum amount of time to wait 
         * while executing (in seconds)
         *
         * @return double
         */
        public function getTimeout()
        {
            return $this->timeout;
        }
        
        /**
         * Sets the timeout
         * 
         * Timeout is a maximum amount of time to wait 
         * while executing (in seconds)
         * 
         * The given timeout should be of type double or int
         * 
         * @param mixed $timeout
         */
        public function setTimeout( $timeout )
        {
            if( !is_double( $timeout ) && !is_int( $timeout ) )
            {
                $timeout = (int)$timeout;
            }
            
            $this->timeout = round( $timeout, 3 );
        }
        
        /**
         * Returns the object representing a set of HTTP authentication options
         *
         * @return Curly\Authentication
         */
        public function authentication()
        {
            return $this->authentication;
        }
        
        /**
         * Returns the collection of cookies associated with this request
         *
         * @return Curly\Cookies\CookieContainer
         */
        public function cookies()
        {
            return $this->cookies;
        }
        
        /**
         * Returns the collection of files that will be uploaded
         *
         * @return Curly\Collections\StringIndexedCollection
         */
        public function files()
        {
            return $this->files;
        }
        
        /**
         * Returns the collection of headers that will be attached to this request
         *
         * @return Curly\Collections\StringIndexedCollection
         */
        public function headers()
        {
            return $this->headers;
        }
        
        /**
         * Returns the collection of additional options used by client adapters
         *
         * @return Curly\Collections\Collection
         */
        public function options()
        {
            return $this->options;
        }
        
        /**
         * Returns the collection of POST vars that will be send
         * 
         * The POST vars will be send only if the request method is POST
         * 
         * @return Curly\Collections\StringIndexedCollection
         */
        public function postVars()
        {
            return $this->postVars;
        }
        
        /**
         * Returns the object representing a set of proxy server options
         *
         * @return Curly\Proxy
         */
        public function proxy()
        {
            return $this->proxy;
        }
        
        /**
         * Indicates whether executing of this request is finished
         *
         * @return bool
         */
        public function isFinished()
        {
            return $this->isFinished;
        }
        
        /**
         * Sets the indication of whether executing of this
         * request is finished
         * 
         * @internal
         * @param bool $isFinished
         */
        public function _setFinished( $isFinished )
        {
            $this->isFinished = (bool)$isFinished;
        }
        
        /**
         * Returns last occured error
         *
         * @return Curly\Error
         */
        public function getError()
        {
            return $this->error;
        }
        
        /**
         * Sets the error
         * 
         * @internal
         * @param Curly\Error $error
         */
        public function _setError( Error $error )
        {
            $this->error = $error;
        }
        
        /**
         * Returns the response object for this request
         *
         * @return Curly\Response
         */
        public function getResponse()
        {
            return $this->response;
        }
        
        /**
         * Sets the response object
         * 
         * @internal
         * @param Curly\Response $response
         */
        public function _setResponse( Response $response = null )
        {
            $this->response = $response;
        }
        
        /**
         * Returns the object of the event that fires, when executing
         * of this request finishes
         *
         * @return Curly\RequestCompletedEvent
         */
        public function requestCompletedEvent()
        {
            return $this->requestCompletedEvent;
        }
    }
}